package com.itm.eventos.controlador.dao.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.inject.Inject;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

import org.apache.log4j.Logger;

import com.itm.eventos.controlador.dao.GrabadorAudioDao;
import com.itm.eventos.utils.Constantes;
import com.itm.eventos.utils.Utilidades;
import com.itm.eventos.vista.dao.VentanaEventosDao;

public class GrabadorAudioDaoImpl implements GrabadorAudioDao {

	private static final long serialVersionUID = 1L;
	private Properties propiedadesAudio;
	private final static Logger logger = Logger.getLogger(GrabadorAudioDaoImpl.class);
	
	@Inject
	private VentanaEventosDao ventanaEventosDao;
	
	
	private boolean stopCapture = false;
	private ByteArrayOutputStream byteArrayOutputStream;
	private AudioFormat audioFormat;
	private TargetDataLine targetDataLine;
	private AudioInputStream audioInputStream;
	private SourceDataLine sourceDataLine;
	private FileOutputStream fsalida;
	private boolean canalAbierto=false;


	public GrabadorAudioDaoImpl() {
		obtenerPropiedades();
	}

	public void grabarAudio() {
		try {
			ventanaEventosDao.imprimirMensajeAreaLog("capturando sonido ...");
			audioFormat = getAudioFormat();			
			DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
			targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
			if (canalAbierto==false) {
				targetDataLine.open(audioFormat);
				canalAbierto=true;
			}
			targetDataLine.start();
			Thread captureThread = new Thread(new CaptureThread());
			captureThread.start();
		} catch (Exception e) {
			logger.error("Ha fallado la captura de audio:" + e.getMessage());
			System.exit(0);
		}
	}

	public void guardarAudio() {
		try {
			String rutaAudio = Constantes.RUTA_CAPTURAS + "/"
				+ Constantes.LOCATION_SOUND + "/"
				+ new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date()).toString()
				+ Constantes.EXT_CAPTURA_SONIDO;
			File file = new File(rutaAudio);
			fsalida = new FileOutputStream(file);
			
			byte audioData[] = byteArrayOutputStream.toByteArray();
			InputStream byteArrayInputStream = new ByteArrayInputStream(audioData);
			AudioFormat audioFormat = getAudioFormat();
			audioInputStream = new AudioInputStream(
				byteArrayInputStream, audioFormat, audioData.length / audioFormat.getFrameSize());
			DataLine.Info dataLineInfo = new DataLine.Info(
				SourceDataLine.class, audioFormat);
			sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
			sourceDataLine.open(audioFormat);
			sourceDataLine.start();

			Thread saveThread = new Thread(new SaveThread());
			saveThread.start();
			sourceDataLine.stop();
			
			//Copia en ruta remota
			Utilidades.copyFileToRemoteLocation(
				rutaAudio, 
				Utilidades.getTmpPathServer()+rutaAudio.substring(rutaAudio.indexOf("/")));
			
			ventanaEventosDao.imprimirMensajeAreaLog("[Captura sonido finalizada correctamente]");
		} catch (Exception e) {
			logger.error("Ha fallado la captura de audio:" + e.getMessage());
			System.exit(0);
		}
	}
	
	private void obtenerPropiedades() {
		try {
			String rutaPropiedades = Constantes.RUTA_CONF + "/" + Constantes.FICH_PROP_AUDIO;
			this.propiedadesAudio = new Properties();
			propiedadesAudio.load(new FileInputStream(rutaPropiedades));
		} catch (FileNotFoundException e1) {
		} catch (IOException e) {}
	}
	
	private AudioFormat getAudioFormat() {
		if (audioFormat==null) {
			float sampleRate = Float.parseFloat(propiedadesAudio.getProperty(Constantes.VAR_sampleRate));
			// 8000,11025,16000,22050,44100
			int sampleSizeInBits = Integer.parseInt(propiedadesAudio.getProperty(Constantes.VAR_sampleSizeInBits)); 
			// 8,16
			int channels = Integer.parseInt(propiedadesAudio.getProperty(Constantes.VAR_channels));
			// 1,2
			boolean signed = Boolean.parseBoolean(propiedadesAudio.getProperty(Constantes.VAR_signed));
			// true,false
			boolean bigEndian = Boolean.parseBoolean(propiedadesAudio.getProperty(Constantes.VAR_bigEndian));
			// true,false
			return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
		}
		else {
			return audioFormat;
		}
	}

	class CaptureThread extends Thread {
		// An arbitrary-size temporary holding buffer
		byte tempBuffer[] = new byte[10000];

		public void run() {
			byteArrayOutputStream = new ByteArrayOutputStream();
			stopCapture = false;
			try {
				while (!stopCapture) {
					int cnt = targetDataLine.read(tempBuffer, 0, tempBuffer.length);
					if (cnt > 0) {
						byteArrayOutputStream.write(tempBuffer, 0, cnt);
					}
				}
				byteArrayOutputStream.close();
			} catch (Exception e) {
				logger.error("Ha fallado la captura de audio:" + e.getMessage());
				System.exit(0);
			}
		}
	}

	class SaveThread extends Thread {
		byte tempBuffer[] = new byte[10000];
		public void run() {
			try {
				if (AudioSystem.isFileTypeSupported(AudioFileFormat.Type.AU, audioInputStream)) {
					AudioSystem.write(audioInputStream,	AudioFileFormat.Type.AU, fsalida);
				}
			} catch (Exception e) {
				logger.error("Ha fallado la captura de audio:" + e.getMessage());
				System.exit(0);
			}
		}
	}
}